package com.mask.im.server.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

/**
 * netty服务器
 *
 * @author jian
 */

@Log4j2
@Component
public class IMNettySocketServer {

    // 从配置文件读取端口，默认8089
    @Value("${netty.port:9095}")
    private int port;

    @Value("${netty.boss-threads:1}")
    private int bossThreads;

    @Value("${netty.worker-threads:0}")
    private int workerThreads;


    @Resource
    private IMChannelInitializer channelInitializer;

    /**
     * Netty服务器启动对象
     */
    private final ServerBootstrap serverBootstrap = new ServerBootstrap();

    // 主线程组（接受客户端连接）
    private NioEventLoopGroup mainGroup;

    // 从线程组（处理读写事件）
    private NioEventLoopGroup subGroup;
    /**
     * 初始化Netty配置（在Bean构造后执行）
     */
    @PostConstruct
    public void maskNettySocketServerInit() {
        log.info("开始初始化Netty服务器配置...");

        // 设置工作线程数
        if (workerThreads <= 0) {
            workerThreads = Runtime.getRuntime().availableProcessors() * 2;
        }

        // 主线程组（接受客户端连接）
        mainGroup = new NioEventLoopGroup(bossThreads);
        // 从线程组（处理读写事件）
        subGroup = new NioEventLoopGroup(workerThreads);

        serverBootstrap
                // 设置线程组
                .group(mainGroup, subGroup)
                // 指定服务器通道类型
                .channel(NioServerSocketChannel.class)
                // 设置通道初始化器
                .childHandler(channelInitializer)
                .option(ChannelOption.SO_BACKLOG, 128)
                .option(ChannelOption.SO_REUSEADDR, true)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childOption(ChannelOption.TCP_NODELAY, true);

        log.info("Netty服务器配置完成 - 端口: {}, Boss线程: {}, Worker线程: {}",
                port, bossThreads, workerThreads);
    }

    public void start() throws InterruptedException {
        try {
            log.info("正在启动Netty服务器...");
            ChannelFuture future = serverBootstrap.bind("0.0.0.0", port).sync();
            if (future.isSuccess()) {
                log.info("Netty服务器启动成功，监听端口: {}", port);
            } else {
                log.error("Netty服务器启动失败，端口: {}", port);
                throw new RuntimeException("Netty服务器启动失败");
            }
        } catch (InterruptedException e) {
            log.error("Netty服务器启动被中断", e);
            Thread.currentThread().interrupt();
            throw new RuntimeException("Netty服务器启动被中断", e);
        } catch (Exception e) {
            log.error("Netty服务器启动异常", e);
            throw new RuntimeException("Netty服务器启动异常", e);
        }
    }


    /**
     * 优雅关闭Netty资源（在Bean销毁前执行）
     */
    @PreDestroy
    public void stop() {
        log.info("开始关闭Netty服务器...");
        // 优雅关闭线程组
        if (mainGroup != null) {
            mainGroup.shutdownGracefully();
        }
        if (subGroup != null) {
            subGroup.shutdownGracefully();
        }
        log.info("Netty服务器已关闭");
    }
}
